using System;
using System.IO;
using System.Net;
using System.Web;
using System.Xml;

using Google.Apps.Provisioning.Authentication;
using Google.Apps.Provisioning.Actions;
using Google.Apps.Provisioning.Utilities;

namespace Google.Apps.Provisioning
{
    /// <summary>
    /// Controls interactions with the Google Provisioning API.  All steps common to each API request
    /// are encapsulated here, and any steps specific to an action (eg, CreateUser) are implemented in the
    /// action class specific to that action (eg, CreateUserAction).  This class will prepare the requestXml
    /// for the Google API, post the request to Google, and retrieve the response.
    /// </summary>
    internal class ActionController
    {
        private string domain;
        private AuthenticationToken securityToken;

        public ActionController( string domain, AuthenticationToken securityToken )
        {
            this.domain = domain;
            this.securityToken = securityToken;
        }

        public ProvisioningResponse Execute( BaseProvisioningAction action )
        {
            string responseXml = IssueRequest( action );
            ProvisioningResponse response = ProcessResponse( action, responseXml );

            return response;
        }

        private string IssueRequest( BaseProvisioningAction action )
        {
            XmlDocument doc = action.GetRequestXmlTemplate();

            XmlNamespaceManager ns = new XmlNamespaceManager( doc.NameTable );
            ns.AddNamespace( "hs", "google:accounts:rest:protocol" );

            doc.SelectSingleNode( "hs:rest/hs:token", ns ).InnerText = securityToken.GetSecurityToken();
            doc.SelectSingleNode( "hs:rest/hs:domain", ns ).InnerText = domain;

            action.ProcessRequestXml( doc, ns );

            string responseXml;
            HttpStatusCode status;

            WebUtility.DoHttpPost( action.ServiceUrl, doc.OuterXml, out status, out responseXml );

            return responseXml;
        }

        private ProvisioningResponse ProcessResponse( BaseProvisioningAction action, string responseXml )
        {
            ProvisioningResponse response = new ProvisioningResponse( responseXml );
            action.Response = response;
            
            XmlDocument doc = new XmlDocument();
            doc.LoadXml( responseXml );

            XmlNamespaceManager ns = new XmlNamespaceManager( doc.NameTable );
            ns.AddNamespace( "hs", "google:accounts:rest:protocol" );

            if ( response.IsSuccess() )
                action.ProcessResponseXml( doc, ns );

            return response;
        }
    }
}
